import re
import threading
from StringIO import StringIO
from sqlalchemy.sql.expression import and_, or_
from xml.dom import minidom

from ivic.core import Logging
from ivic.vsched.Model import *
from ivic.vsched.Interface import Interface
from ivic.core.Utils import GenUUID, string_trim

logger = Logging.get_logger('ivic.vsched.Impl')

tableNames      = {
    VclusterTemp: 'vCluster Template',
    VlabTemp: 'vLab Template',
    VmTemp: 'VM Template',
    VirtualClusterInstance: 'vCluster Instance', 
    VlabInstance: 'vLab Instance', 
    VirtualMachineInstance: 'VM Instance',
    Vswitch: 'vSwitch',
    Nic: 'NIC'
}

tableMapper2Key = {
    VclusterTemp: 'vCluster', 
    VlabTemp: 'vLab', 
    VmTemp: 'vTemplate',
    VirtualClusterInstance: 'vCluster', 
    VlabInstance: 'vLab', 
    VirtualMachineInstance: 'VM',
    Vswitch: 'vSwitch',
    Nic: 'NIC'
}

templateKey2Mapper = {'vCluster': VclusterTemp, 'vLab': VlabTemp, 'vTemplate': VmTemp}
templateMappers    = templateKey2Mapper.values()

instanceKey2Mapper = {
    'vCluster': VirtualClusterInstance, 
    'vLab': VlabInstance,
    'VM': VirtualMachineInstance,
    'vSwitch': Vswitch,
    'NIC': Nic
}
instanceMappers    = instanceKey2Mapper.values()

class Getter:

    def __init__(self, mapper_dict):
        self.mappers = mapper_dict.values()
        self.mapper_dict = mapper_dict
        self.reverse_dict = {}
        for k, v in mapper_dict.items():
            self.reverse_dict[v] = k
        
    def to_key(self, obj):
        return '%s@%d' % (self.reverse_dict[type(obj)], obj.id)

    def by_key(self, key, session):
        key_type, strid = key.split('@')
        try:
            id = int(strid)
            mapper = self.mapper_dict[key_type]
            obj = session.query(mapper).get(id)
            if not obj:
                raise LookupError, 'template with id %d not found' % id
            return obj
        except ValueError:
            raise LookupError, 'bad id value %s' % strid
        except KeyError:
            raise LookupError, 'bad key type %s' % key_type
    
    def by_uuid(self, uuid, session):
        rset = self.by_uuids(uuid, session)  
        if len(rset) != 1:
            raise LookupError, 'bad uuid %s, found %d record alike' % (uuid, len(rset))
        return rset[0]
    
    def by_uuids(self, uuid, session):
        if len(uuid) != 36:
            newuuid = uuid[:35] + '%'
        else:
            newuuid = uuid 
        rset = []
        for mapper in self.mappers:
            if not hasattr(mapper, 'uuid'):
                continue
            if '%' in newuuid:
                expr = mapper.uuid.like(newuuid)
            else:
                expr = mapper.uuid == newuuid
            rset += session.query(mapper).filter(expr).all()
        return rset

TemplateGetter = Getter(templateKey2Mapper)
InstanceGetter = Getter(instanceKey2Mapper)

class ImplError(Exception):
    pass

def exceptionWrapper(fun):
    def __wrapper(*args, **kwargs):
        try:
            return fun(*args, **kwargs)
        except ImplError:
            raise
        except Exception, e:
            logger.exception(e)
            raise ImplError, e.message
    return __wrapper

class Impl(Interface):

    def __init__(self, session):
        self.lock = threading.Lock()
        self.s = session

    @exceptionWrapper
    def importTemplate(self, xml):
        '''importTemplate -- import XML into Portal's database
    Return Value
        Integer 0 - for successfully import
    Throws XmlImportError'''
        self.lock.acquire()
        try:
            import_xml(xml, self.s)
            self.lock.release()
        except:
            self.lock.release()

    def __do_template_header(self, iob):
        print >> iob, '%-13s %-36s %-18s %s' % ('ID', 'UUID', 'Name', 'Description')
    
    def __do_template_list(self, iob, mapper):
        rset = self.s.query(mapper).order_by(mapper.id)
        for record in rset:
            key = '%s@%d' % (tableMapper2Key[mapper], record.id)
            uuid = string_trim(record.uuid, 36)
            name = string_trim(record.name, 18)
            description = string_trim(record.description)
            print >> iob, '%-13s %-36s %-18s %s' % (key, uuid, name, description)  

    def __do_instance_header(self, iob):
        print >> iob, '%-13s %-36s %-18s %s' % ('ID', 'UUID', 'Name', 'Status')

    def __try_getattr(self, obj, attr):
        try:
            return getattr(obj, attr)
        except:
            return 'No such field'
    
    def __do_instance_list(self, iob, mapper):
        rset = self.s.query(mapper).order_by(mapper.id)
        for record in rset:
            key = '%s@%d' % (tableMapper2Key[mapper], record.id)
            uuid = string_trim(self.__try_getattr(record, 'uuid'), 36)
            name = string_trim(self.__try_getattr(record, 'name'), 18)
            status = self.__try_getattr(record, 'status')
            print >> iob, '%-13s %-36s %-18s %s' % (key, uuid, name, status)

    def __do_job_header(self, iob):
        print >> iob, '%-3s %-36s %-18s %s' % ('ID', 'UUID', 'Title', 'Status')

    def __do_job_list(self, iob, mapper):
        rset = self.s.query(mapper).order_by(mapper.id)
        for record in rset:
            id = record.id
            uuid = string_trim(record.uuid, 36)
            name = record.title
            status = record.status
            print >> iob, '%-3s %-36s %-18s %s' % (id, uuid, name, status)
            
    @exceptionWrapper
    def listTemplate(self):
        '''listTemplate -- list template in Portal's database
    Return Value:
        String - a list containing each template's UUID, Type, Name'''
        self.lock.acquire()
        try:
            iob = StringIO()
            self.__do_template_header(iob)
            for mapper in templateMappers:
                self.__do_template_list(iob, mapper)
            self.lock.release()
            return iob.getvalue()
        except:
            self.lock.release()

    @exceptionWrapper
    def listTemplate_ByType(self, typ):
        '''listTemplate_ByType -- list template by `type`
    Argument `type` - vLabTemplate, vClusterTemplate, vTemplate
    Return Value:
        String - a list containing each template's UUID, Type, Name
    Throws LookupError - for invalid `type`'''
        mapper = templateKey2Mapper[typ]
        '''
        iob = StringIO()
        self.__do_template_header(iob)
        self.__do_template_list(iob, mapper)
        return iob.getvalue()
        '''
        self.lock.acquire()
        try:
            rset = self.s.query(mapper).order_by(mapper.id)
            dict = {}
            for record in rset:
                dict[record.uuid] = record.name
            self.lock.release()
            return str(dict)
        except:
            self.lock.release()

    def listVmi_ByVlab(self, vlabInstance_uuid):
        self.lock.acquire()
        try:
            vlab_instance_id = self.s.query(VlabInstance).filter(VlabInstance.uuid == vlabInstance_uuid)[0].id
            rset = self.s.query(VirtualMachineInstance).filter(VirtualMachineInstance.vlab_instance_id == vlab_instance_id)
            re = ''
            for vmi in rset:
                vmc = self.s.query(VirtualMachineContainer).get(vmi.virtual_machine_container_id)
                if vmi.vnc_port:
                    re = re + vmc.address + ':' + vmi.vnc_port + ';'
            self.lock.release()
            return re
        except:
            self.lock.release()

    def listVmi_ByVcluster(self, vclusterInstance_uuid):
        self.lock.acquire()
        try:
            vcluster_instance_id = self.s.query(VirtualClusterInstance).filter(VirtualClusterInstance.uuid == vclusterInstance_uuid)[0].id
            rset = self.s.query(VirtualMachineInstance).filter(VirtualMachineInstance.virtual_cluster_instance_id == vcluster_instance_id)
            re = ''
            for vmi in rset:
                vmc = self.s.query(VirtualMachineContainer).get(vmi.virtual_machine_container_id)
                if vmi.vnc_port:
                    re = re + vmc.address + ':' + vmi.vnc_port + ';'
            self.lock.release()
            return re
        except:
            self.lock.release()

    def listVSwitch_ByVlab(self, vlabInstance_uuid):
        self.lock.acquire()
        try:
            vlab_instance_id = self.s.query(VlabInstance).filter(VlabInstance.uuid == vlabInstance_uuid)[0].id
            rset = self.s.query(Vswitch).filter(Vswitch.vlab_instance_id == vlab_instance_id)
            re = ''
            for vswitch in rset:
                vmc = self.s.query(VirtualMachineContainer).get(vswitch.virtual_machine_container_id)
                re = re + vswitch.uuid + ':' + vmc.address + ';'
            self.lock.release()
            return re
        except:
            self.lock.release()

    def listVSwitch_ByVcluster(self, vclusterInstance_uuid):
        self.lock.acquire()
        try:
            vcluster_instance_id = self.s.query(VirtualClusterInstance).filter(VirtualClusterInstance.uuid == vclusterInstance_uuid)[0].id
            rset = self.s.query(Vswitch).filter(Vswitch.virtual_cluster_instance_id == vcluster_instance_id)
            re = ''
            for vswitch in rset:
                vmc = self.s.query(VirtualMachineContainer).get(vswitch.virtual_machine_container_id)
                re = re + vswitch.uuid + ':' + vmc.address +';'
            self.lock.release()
            return re
        except:
            self.lock.release()

    def listVlabInstance_ByTemp(self, uuid):
        self.lock.acquire()
        try:
            vlab_temp_id = self.s.query(VlabTemp).filter(VlabTemp.uuid == uuid)[0].id
            rset = self.s.query(VlabInstance).filter(VlabInstance.vlab_temp_id == vlab_temp_id)
            dict = {}
            for record in rset:
                dict[record.uuid] = record.name
            self.lock.release()
            return str(dict)
        except:
            self.lock.release()

    def listVmTemp(self):
        self.lock.acquire()
        try:
            rset = self.s.query(VmTemp).order_by(VmTemp.id)
            dict = {}
            for record in rset:
                dict[record.uuid] = record.name
            self.lock.release()
            return str(dict)
        except:
            self.lock.release()

    ############################################################
    def listAllVclusters(self):
        self.lock.acquire()
        try:
            vclusters = self.s.query(VirtualClusterInstance).order_by(VirtualClusterInstance.id)
            list_vcluster = list(vclusters)
            invalid_flag = 1
            all_vcluster_uuids = ''
            if (len(list_vcluster) == 0):
                return 'NULL'
            else:
                for vcluster in vclusters:
                    vct = self.s.query(VclusterTemp).filter(VclusterTemp.id == vcluster.vcluster_temp_id)[0]
                    if (vct.capabilities == 'vsaas'):
                        if (vcluster.status != 'invalid'):
                            all_vcluster_uuids = all_vcluster_uuids + vcluster.uuid + ';'
                            invalid_flag = 0
            self.lock.release()
            if (invalid_flag == 1):
                return 'NULL'
            else:
                return all_vcluster_uuids[:-1]
        except:
            self.lock.release()
    #############################################################        

    def getVmCreateTime(self, uuid):
        self.lock.acquire()
        try:
            vm = self.s.query(VirtualMachineInstance).filter(VirtualMachineInstance.uuid == uuid)[0]
            self.lock.release()
            return str(vm.created_at)
        except:
            self.lock.release()

    def getVmRecentStartTime(self, uuid):
        self.lock.acquire()
        try:
            vm = self.s.query(VirtualMachineInstance).filter(VirtualMachineInstance.uuid == uuid)[0]
            self.lock.release()
            return str(vm.updated_at)
        except:
            self.lock.release()

    @exceptionWrapper
    def showTemplate(self, uuid):
        '''showTemplate -- show template info by UUID
    Return Value:
        String - XML information of a template
    Throws LookupError - for invalid `key`'''
        self.lock.acquire()
        try:
            obj = TemplateGetter.by_uuid(uuid, self.s)
            self.lock.release()
            return export_xml(obj, self.s)
        except:
            self.lock.release()

    @exceptionWrapper
    def showInstance(self, uuid):
        '''showInstance -- show instance info by UUID
    Return Value:
        String - XML information of a instance
    Throws LookupError - for invalid `key`'''
        self.lock.acquire()
        try:
            obj = InstanceGetter.by_uuid(uuid, self.s)
            self.lock.release()
            return export_xml(obj, self.s)
        except:
            self.lock.release()
        
    @exceptionWrapper
    def showTemplate_ByKey(self, key):
        '''showTemplate_ByKey -- show template info by `key`
    Argument `key` - vClusterTemplate@<int>, vLabTempate@<int>, vTemplate@<int>
    Return Value:
        String - XML information of a template
    Throws LookupError - for invalid `key`'''
        self.lock.acquire()
        try:
            obj = TemplateGetter.by_key(key, self.s)
            self.lock.release()
            return export_xml(obj, self.s)
        except:
            self.lock.release()

    @exceptionWrapper
    def set_worknode_count(self, uuid, new_count):
        vcluster_temp = self.s.query(VclusterTemp).filter(VclusterTemp.uuid == uuid)[0]
        vlt_vmt = self.s.query(VclusterTempsVmTemp).filter(and_(VclusterTempsVmTemp.vcluster_temp_id == vcluster_temp.id, VclusterTempsVmTemp.ref_type == 'worknode'))[0]
        vlt_vmt.count = new_count
        vcluster_temp.node_num = new_count + 1
        self.s.flush()

    @exceptionWrapper
    def set_vct_vmt(self, vct_uuid, vmt_uuid):
        vct = self.s.query(VclusterTemp).filter(VclusterTemp.uuid == vct_uuid)[0]
        vmt = self.s.query(VmTemp).filter(VmTemp.uuid == vmt_uuid)[0]
        vlt_vmt = self.s.query(VclusterTempsVmTemp).filter(and_(VclusterTempsVmTemp.vcluster_temp_id == vct.id, VclusterTempsVmTemp.ref_type == 'headnode'))[0]
        vlt_vmt.vm_temp_id = vmt.id
        vnode = generate_vnode(vmt)
        vlt_vmt.settings = vnode
        self.s.flush()

    @exceptionWrapper
    def get_vcluster_network_info(self, uuid):
        vli = self.s.query(VirtualClusterInstance).filter(VirtualClusterInstance.uuid == uuid)[0]
        vmis = self.s.query(VirtualMachineInstance).filter(VirtualMachineInstance.virtual_cluster_instance_id == vli.id).order_by(VirtualMachineInstance.node_index).all()
        s = ''
        for vmi in vmis:
            doc = minidom.parseString(vmi.settings)
            s = s + doc.getElementsByTagName('Address')[0].firstChild.data + ':'
            s = s[:-1]
        return s

    @exceptionWrapper
    def get_vcluster_dnat_info(self, uuid):
        vcluster = self.s.query(VirtualClusterInstance).filter(VirtualClusterInstance.uuid == uuid)[0]
        res = ''
        for vmi in self.s.query(VirtualMachineInstance).filter(VirtualMachineInstance.virtual_cluster_instance_id == vcluster.id):
            dnets = self.s.query(Dnet).filter(Dnet.virtual_machine_instance_id == vmi.id)
            list_dnets = list(dnets)
            if (len(list_dnets) == 0):
                return 'NULL'
            else:    
                for dnet in dnets:
                    res = res + vmi.uuid + ':' + str(vmi.id) + ',' +dnet.protocol + ',' +dnet.internal_ip + ':' + str(dnet.internal_port) + ',' + dnet.external_ip + ':' + str(dnet.external_port) + ';'
        res = res[:-1]
        logger.debug("********%s"%res)
        return res

    
    #add by yangry :add new job for vcluster_scale
    @exceptionWrapper
    def to_do_vcluster_scale(self, uuid, op, num):
        vcluster = self.s.query(VirtualClusterInstance).filter(VirtualClusterInstance.uuid == uuid)[0]
        vm_indexes = []
        for vm in self.s.query(VirtualMachineInstance).filter(VirtualMachineInstance.virtual_cluster_instance_id == vcluster.id):
            vm_indexes.append(vm.node_index)

        vm = VirtualMachineInstance()
        vm.uuid = GenUUID()
        vm.status = 'invalid'
        vm.virtual_cluster_instance_id = vcluster.id
        #get its brother as template.
        existent_vm = self.s.query(VirtualMachineInstance).filter(VirtualMachineInstance.virtual_cluster_instance_id == vcluster.id)[0]
        #set vm's vm_temp_id
        vm.vm_temp_id = existent_vm.vm_temp_id
        j = 0
        while j <= 200:
            if j not in vm_indexes:
                index = j
                break
            j = j + 1
        vm.node_index = index
        doc = minidom.parseString(existent_vm.settings).documentElement
        #we can get other brother vm as a reference.
        ref_address = doc.getElementsByTagName("Address")[0].firstChild.data
        ref_hostname = doc.getElementsByTagName("Hostname")[0].firstChild.data
        #then we count new node's addr and hostname
        segment = ref_address.split('.')
        address = ".".join(segment[0:3])+'.'+str(index + 100)
        hostname = "cu"+str(index)
        vm.hostname = hostname
        doc.getElementsByTagName('Hostname')[0].firstChild.nodeValue = hostname
        doc.getElementsByTagName('Address')[0].firstChild.nodeValue = address
        vm.settings = doc.toxml()
        
        self.s.save(vm)
        self.s.flush()

        old_ports = []

        vswitch = self.s.query(Vswitch).filter(Vswitch.virtual_cluster_instance_id == vcluster.id)[0]
        logger.info("***********")
        logger.info(vswitch.uuid)
        logger.info("***********")
        for dnet in self.s.query(Dnet).filter(Dnet.vswitch_id == vswitch.id):
            old_ports.append(dnet.external_port)
        #then we create dnat info.
        iptables = "tcp:8080,tcp:5900,tcp:5901,tcp:5902,tcp:5903,tcp:5904,tcp:5905,tcp:5906,tcp:5907,tcp:5908,tcp:5909,tcp:5910"
        start_cmds = []
        stop_cmds = []
        ip_table = iptables.split(",")
        for dnat in ip_table:
            vgateway_dnat = Dnet()
            vgateway_dnat.virtual_machine_instance_id = vm.id
            vgateway_dnat.vswitch_id = vswitch.id
            vswitch_net = vswitch.ip.split(".")
            vgateway_dnat.internal_ip = (".").join(vswitch_net[0:3])+"."+str(int(vm.hostname[2:])+100)
            vgateway_dnat.internal_port = int(dnat.split(":")[1])
            vgateway_dnat.protocol = dnat.split(":")[0]
            existent_dnat = self.s.query(Dnet).filter(Dnet.virtual_machine_instance_id == existent_vm.id)[0]
            #vgateway_dnat.external_ip = existent_dnat.external_ip
            #i = 60000
            #while i <= 61000:
            #    if i not in old_ports:
            #        vgateway_dnat.external_port = i
            #        break
            #    i = i + 1
            #old_ports.append(i)
            self.s.save(vgateway_dnat)
            self.s.flush()
            
        new_job = Job()
        new_job.uuid = GenUUID()
        id = vcluster.id
        new_job.user_id = vcluster.user_id
        new_job.title = '' + op + ' vcluster:' + str(id)
        new_job.description = '' + op + ' vcluster:' + str(id)
        new_job.job_type = 'vcluster_'+op
        new_job.content = 'id:'+ str(id)+',newcount:'+num
        new_job.status = 'pending'
        new_job.job_info = ''
        logger_content = new_job.uuid+' '+str(id)+' '+str(new_job.user_id)+' '+new_job.title+' '+new_job.description+' '+new_job.job_type+' '+new_job.content+' '+new_job.status+' '+new_job.job_info
        logger.info("********todo_vcluster_scale%s"%logger_content)
        #new_job = Job(job_uuid, id, user_id, title, description, job_type, content, status, created_at, updated_at, job_info)
        self.s.save(new_job)
        #logger.debug('saving %s', new_job)
        self.s.flush()
        #logger.debug("********%s"%logger_content)
        return logger_content



    @exceptionWrapper
    def get_vcluster_mu_vnc(self, uuid):
        vli = self.s.query(VirtualClusterInstance).filter(VirtualClusterInstance.uuid == uuid)[0]
        vmis = self.s.query(VirtualMachineInstance).filter(VirtualMachineInstance.virtual_cluster_instance_id == vli.id).order_by(VirtualMachineInstance.node_index).all()
        vmc_x = self.s.query(VirtualMachineContainer).get(vmis[0].virtual_machine_container_id)
        s = vmc_x.address + ':' + vmis[0].vnc_port
        return s

    @exceptionWrapper
    def get_vcluster_mu_uuid(self, uuid):
        vli = self.s.query(VirtualClusterInstance).filter(VirtualClusterInstance.uuid == uuid)[0]
        vmi = self.s.query(VirtualMachineInstance).filter(VirtualMachineInstance.virtual_cluster_instance_id == vli.id).order_by(VirtualMachineInstance.node_index)[0]
        return vmi.uuid

    @exceptionWrapper
    def get_vcluster_status(self, uuid):
        vli = self.s.query(VirtualClusterInstance).filter(VirtualClusterInstance.uuid == uuid)[0]
        vmis = self.s.query(VirtualMachineInstance).filter(VirtualMachineInstance.virtual_cluster_instance_id == vli.id).order_by(VirtualMachineInstance.node_index).all()
        s = vli.name + ':' + vli.status + ';'
        for vmi in vmis:
           s = s + vmi.hostname + ':' + vmi.status + ';'
        return s

    @exceptionWrapper
    def removeTemplate(self, uuid):
        '''removeTemplate -- remove template according to specified uuid, also remove related instances'''
        self.lock.acquire()
        try:
            obj = TemplateGetter.by_uuid(uuid, self.s)
            self.lock.release()
            return remove_template(obj, self.s)
        except:
            self.lock.release()

    @exceptionWrapper
    def removeTemplates(self, uuid):
        '''removeTemplates -- remove multiple template according to partial uuid, also remove related instances'''
        self.lock.acquire()
        try:
            objs = TemplateGetter.by_uuids(uuid, self.s)
            for obj in objs:
                remove_template(obj, self.s)
            self.lock.release()
        except:
            self.lock.release()
    
    @exceptionWrapper
    def removeTemplate_ByKey(self, key):
        '''removeTemplate -- remove template according to specified key, also remove related instances'''
        self.lock.acquire()
        try:
            obj = TemplateGetter.by_key(key, self.s)
            self.lock.release()
            return remove_template(obj, self.s)
        except:
            self.lock.release()

    @exceptionWrapper
    def listInstance(self):
        '''listInstance -- list instance in Portal's database
    Return Value:
        String - a list containing each instance's UUID, Type, Name'''
        self.lock.acquire()
        try:
            iob = StringIO()
            self.__do_instance_header(iob)
            for mapper in instanceMappers:
                self.__do_instance_list(iob, mapper)
            self.lock.release()
            return iob.getvalue()
        except:
            self.lock.release()

    @exceptionWrapper
    def listInstance_ByType(self, typ):
        '''listInstance_ByType -- list instance by `type`
    Argument `type` - vLabInstance, vClusterInstance, vInstance
    Return Value:
        String - a list containing each instance's UUID, Type, Name
    Throws LookupError - for invalid `type`'''
        self.lock.acquire()
        try:
            mapper = instanceKey2Mapper[typ]
            iob = StringIO()
            self.__do_instance_header(iob)
            self.__do_instance_list(iob, mapper)
            self.lock.release()
            return iob.getvalue()
        except:
            self.lock.release()

    @exceptionWrapper
    def listJob(self):
        '''listJob -- list Job instances in Portal's database
    Return Value:
        String - a list containing each job's UUID, Type, Name'''
        iob = StringIO()
        self.__do_job_header(iob)
        self.__do_job_list(iob, Job)
        self.lock.release()
        return iob.getvalue()

    @exceptionWrapper
    def listTask(self):
        '''listTask -- list Task instances in Portal's database
    Return Value:
        String - a list containing each job's UUID, Type, Name'''
        iob = StringIO()
        self.__do_job_header(iob)
        self.__do_job_list(iob, Task)
        self.lock.release()
        return iob.getvalue()

    @exceptionWrapper
    def removeInstance(self, uuid):
        '''removeInstance -- remove instance according to specified uuid, also remove related instances'''
        self.lock.acquire()
        try:
            obj = InstanceGetter.by_uuid(uuid, self.s)
            self.lock.release()
            return remove_instance(obj, self.s)
        except:
            self.lock.release()

    @exceptionWrapper
    def removeInstances(self, uuid):
        '''removeInstances -- remove multiple instance according to partial uuid, also remove related instances'''
        self.lock.acquire()
        try:
            objs = InstanceGetter.by_uuids(uuid, self.s)
            for obj in objs:
                remove_instance(obj, self.s)
            self.lock.release()
        except:
            self.lock.release()
    
    @exceptionWrapper
    def removeInstance_ByKey(self, key):
        '''removeInstance -- remove instance according to specified key, also remove related instances'''
        self.lock.acquire()
        try:
            obj = InstanceGetter.by_key(key, self.s)
            self.lock.release()
            return remove_instance(obj, self.s)
        except:
            self.lock.release()

    def __generate_job(self, instance, optype):
        #self.__change_state(instance, optype)
        jobMapper2Key = {VirtualClusterInstance: 'vcluster', VlabInstance: 'vlab'}
        instance_type = jobMapper2Key[type(instance)]
        job = Job()
        job.uuid = GenUUID()
        job.content = 'id:%d' % instance.id
        job.description = '%s %s %s' % (optype, instance_type, job.content)
        job.title = job.description #'%s %s %s' % (optype, instance_type, instance.name)
        job.job_type = '%s_%s' % (instance_type, optype)
        job.user_id = instance.user_id # imported from Model.*
        job.status = 'pending'
        self.s.save(job)
        logger.debug('saving %s', job)
        self.s.flush()
        return job

    @exceptionWrapper
    def deployV(self, template_uuid, param):
        '''deployV_PhaseOne -- deployV phase 1: generate VM and VSwitch instances, and job
    Return Value:
        jobid - if successful, return jobid for deployV phase 2 
    Throws LookupError - for invalid template uuid'''
        self.lock.acquire()
        try:
            template = TemplateGetter.by_uuid(template_uuid, self.s)
            if type(template) == VmTemp:
                raise LookupError, 'no vCluster/vLab found with uuid:%s' % template_uuid
            instance = generate_instance(template, self.s, param)
            job = self.__generate_job(instance, 'deploy')
            self.lock.release()
            return job.id, instance.uuid
        except:
            self.lock.release()

    @exceptionWrapper
    def deployV_ByKey(self, template_key):
        '''deployV_ByKey -- deployV phase 1: generate VM and VSwitch instances, and job
    Return Value:
        jobid - if successful, return jobid for deployV phase 2 
    Throws LookupError - for invalid template uuid'''
        self.lock.acquire()
        try:
            template = TemplateGetter.by_key(template_key, self.s)
            if type(template) == VmTemp:
                raise LookupError, 'no vCluster/vLab found with uuid:%s' % template_uuid
            instance = generate_instance(template, self.s)
            job = self.__generate_job(instance, 'deploy')
            self.lock.release()
            return job.id
        except:
            self.lock.release()

    @exceptionWrapper
    def redeployV(self, uuid):
        '''redeployV_PhaseOne -- deployV: generate job to start vLab/vCluster, assume instance already exists
    Return Value:
        jobid - if successful, return jobid for redeployV phase 2 
    Throws LookupError - for invalid template uuid'''
        self.lock.acquire()
        try:
            instance = InstanceGetter.by_uuid(uuid, self.s)
            job = self.__generate_job(instance, 'deploy')
            self.lock.release()
            return job.id
        except:
            self.lock.release()

    @exceptionWrapper
    def redeployV_ByKey(self, key):
        '''redeployV_ByKey -- deployV: generate job to start vLab/vCluster, assume instance already exists
    Return Value:
        jobid - if successful, return jobid for redeployV phase 2 
    Throws LookupError - for invalid template uuid'''
        self.lock.acquire()
        try:
            instance = InstanceGetter.by_key(key, self.s)
            job = self.__generate_job(instance, 'deploy')
            self.lock.release()
            return job.id
        except:
            self.lock.release()

    @exceptionWrapper
    def startV(self, uuid):
        '''startV_PhaseOne -- startV phase 1: generate job to start vLab/vCluster
    Return Value:
        jobid - if successful, return jobid for startV phase 2 
    Throws LookupError - for invalid template uuid'''
        self.lock.acquire()
        try:
            instance = InstanceGetter.by_uuid(uuid, self.s)
            job = self.__generate_job(instance, 'start')
            self.lock.release()
            return job.id
        except:
            self.lock.release()

    @exceptionWrapper
    def startV_ByKey(self, key):
        '''startV_ByKey -- startV phase 1: generate job to start vLab/vCluster
    Return Value:
        jobid - if successful, return jobid for startV phase 2 
    Throws LookupError - for invalid template key'''
        self.lock.acquire()
        try:
            instance = InstanceGetter.by_key(key, self.s)
            job = self.__generate_job(instance, 'start')
            self.lock.release()
            return job.id
        except:
            self.lock.release()
    
    @exceptionWrapper
    def stopV(self, uuid):
        '''stopV_PhaseOne -- stopV phase 1: generate job to stop vLab/vCluster
    Return Value:
        jobid - if successful, return jobid for stopyV phase 2 
    Throws LookupError - for invalid template uuid'''
        self.lock.acquire()
        try:
            instance = InstanceGetter.by_uuid(uuid, self.s)
            job = self.__generate_job(instance, 'stop')
            self.lock.release()
            return job.id
        except:
            self.lock.release()

    @exceptionWrapper
    def stopV_ByKey(self, key):
        '''stopV_ByKey -- stopV phase 1: generate job to stop vLab/vCluster
    Return Value:
        jobid - if successful, return jobid for stopyV phase 2 
    Throws LookupError - for invalid template key'''
        self.lock.acquire()
        try:
            instance = InstanceGetter.by_key(key, self.s)
            job = self.__generate_job(instance, 'stop')
            self.lock.release()
            return job.id
        except:
            self.lock.release()
    
    @exceptionWrapper
    def undeployV(self, uuid):
        '''undeployV_PhaseOne -- undeploy phase 1: generate job to undeploy vLab/vCluster
    Return Value:
        jobid - if successful, return jobid for undeployV phase 2 
    Throws LookupError - for invalid template uuid'''
        self.lock.acquire()
        try:
            instance = InstanceGetter.by_uuid(uuid, self.s)
            job = self.__generate_job(instance, 'undeploy')
            self.lock.release()
            return job.id
        except:
            self.lock.release()

    @exceptionWrapper
    def undeployV_ByKey(self, key):
        '''undeployV_ByKey -- undeploy phase 1: generate job to undeploy vLab/vCluster
    Return Value:
        jobid - if successful, return jobid for undeployV phase 2 
    Throws LookupError - for invalid template uuid'''
        self.lock.acquire()
        try:
            instance = InstanceGetter.by_key(key, self.s)
            job = self.__generate_job(instance, 'undeploy')
            self.lock.release()
            return job.id
        except:
            self.lock.release()
